/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package expression;

import core.Node;
import core.UnsatException;
import domain.Domain;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author ddoose
 */
public abstract class IntExpr {
    protected Node node;
    protected int id;
    protected Domain current;
    protected Domain target;
    
    public IntExpr(Node n) {
        node = n;
        id = n.getId();
    }
    
    /*
     *   ----------------------------------------
     *             CONSTRUCTEURS
     *   ----------------------------------------
     */
    public IntExpr(Node n, IntExpr p) {
        node = n;
        id = n.getId();

        n.addDependecy(id, p.getId());
    }
    
    public IntExpr(Node n, IntExpr[] p) {
        node = n;
        id = n.getId();

        for (IntExpr e: p) {
            n.addDependecy(id, e.getId());
        }
    }
    
    /*
     *   ----------------------------------------
     *             ACCESSEURS
     *   ----------------------------------------
     */
    public int getId() {
        return id;
    }
    
    public void setId(int i) {
        id = i;
    }
    
    public abstract boolean same(IntExpr i);
    
    public List<Integer> getParameters() {
        List<Integer> temp = node.getNexts(id);
        if (temp == null) {
            temp = new ArrayList<Integer>();
        }
        return temp;
    }
    
    
    public List<Integer> getPrevious() {
        List<Integer> temp = node.getPrevs(id);
        if (temp == null) {
            temp = new ArrayList<Integer>();
        }
        return temp;
    }
    
    public boolean sameParameters(IntExpr i) {
        return node.sameNext(id, i.id);
    }

    /*
     *   ------------------------------ ----------
     *             ACCESSEURS DOMAIN
     *   ----------------------------------------
     */
    public Domain getCurrent() {
        return current;
    }
    
    public Domain getTarget() {
        return target;
    }
    
    /*
     *   ----------------------------------------
     *        PROPAGATIONS & EVALUATIONS
     *   ----------------------------------------
     */
    public void reduceCurrent(Domain d) throws UnsatException {
        Domain newD = current.inter(d);
                
        if (!newD.equals(current)) {
            
            if (newD.isEmpty() || newD.disjoint(target)) {
                throw new UnsatException(this);
            }
            
            if (newD.isValue() && !(this instanceof Variable)) {
                node.replaceWithValue(this, newD.getValue());
            }
            else {
                current = newD;
            }
            
            for (int p: getPrevious()) {
                node.addEvaluation(p);
            }
        }
    }
    
    public void reduceTarget(Domain d) throws UnsatException {
        Domain newD = target.inter(d);
        
        if (!newD.equals(target)) {
            
            if (newD.isEmpty() || newD.disjoint(current)) {
                throw new UnsatException(this);
            }
            else {
                target = newD;
                node.addPropagation(id);
            }
            
            for (int i: getParameters()) {
                node.addPropagation(i);
            }
        }
    }
        
    public abstract void eval() throws UnsatException;
    
    public abstract void propagate() throws UnsatException;
    
    public abstract boolean reduce();
    
    public abstract IntExpr clone(Node node);
    
    public void clone(IntExpr i) {
        id = i.getId();
        current = i.getCurrent();
        target = i.getTarget();
    }
    
    public abstract String toString();
    
    public abstract String pretty();
}
